package tinyiotserver

import (
	"container/list"
	"sync"
)

type Queue interface {
	Len() int
	PushFront(msg *Message)
	PushBack(msg *Message)
	PopFront() (*Message, bool)
	PopBack() (*Message, bool)
	Front() (*Message, bool)
	Back() (*Message, bool)
	Wait() <-chan struct{}
	Size() int
}

type TopicQueue struct {
	Queue
	Topic string
}

//同步队列
func NewSyncQueue(q Queue) Queue {
	sq := &syncQueue{
		Queue: q,
	}
	return sq
}

//同步阻塞队列
func NewSyncBlockingQueue(q Queue) Queue {
	bq := &blockingQueue{
		Queue:  q,
		exists: make(chan struct{}),
	}
	if q.Len() > 0 {
		bq.dataExists()
	}
	sbq := NewSyncQueue(bq)
	return sbq
}

//阻塞队列
type blockingQueue struct {
	Queue
	exists chan struct{}
}

func (q *blockingQueue) PushFront(msg *Message) {
	q.Queue.PushFront(msg)
	q.dataExists()
}

func (q *blockingQueue) dataExists() {
	select {
	case <-q.exists:
	default:
		close(q.exists)
	}
}

func (q *blockingQueue) dataEmpty() {
	select {
	case <-q.exists:
		q.exists = make(chan struct{})
	default:
	}
}

func (q *blockingQueue) Wait() <-chan struct{} {
	return q.exists
}

func (q *blockingQueue) PushBack(msg *Message) {
	q.Queue.PushBack(msg)
	q.dataExists()
}

func (q *blockingQueue) PopFront() (*Message, bool) {
	msg, found := q.Queue.PopFront()
	if !found {
		q.dataEmpty()
	}
	return msg, found
}

func (q *blockingQueue) PopBack() (*Message, bool) {
	msg, found := q.Queue.PopBack()
	if !found {
		q.dataEmpty()
	}
	return msg, found
}

type syncQueue struct {
	Queue
	lock sync.RWMutex
}

func (q *syncQueue) Len() int {
	q.lock.RLock()
	defer q.lock.RUnlock()
	return q.Queue.Len()
}

func (q *syncQueue) PushFront(msg *Message) {
	q.lock.Lock()
	defer q.lock.Unlock()
	q.Queue.PushFront(msg)
}

func (q *syncQueue) PushBack(msg *Message) {
	q.lock.Lock()
	defer q.lock.Unlock()
	q.Queue.PushBack(msg)
}

func (q *syncQueue) PopFront() (*Message, bool) {
	q.lock.Lock()
	defer q.lock.Unlock()
	return q.Queue.PopFront()
}

func (q *syncQueue) PopBack() (*Message, bool) {
	q.lock.Lock()
	defer q.lock.Unlock()
	return q.Queue.PopBack()
}

func (q *syncQueue) Front() (*Message, bool) {
	q.lock.RLock()
	defer q.lock.RUnlock()
	return q.Queue.Front()
}

func (q *syncQueue) Back() (*Message, bool) {
	q.lock.RLock()
	defer q.lock.RUnlock()
	return q.Queue.Back()
}

func (q *syncQueue) Wait() <-chan struct{} {
	return q.Queue.Wait()
}

func NewOrderQueue(maxLen int) Queue {
	q := NewListQueue(maxLen)
	oq := &orderByMsgNoQueue{
		listQueue: q.(*listQueue),
	}
	return oq
}

// orderByMsgNoQueue 按照消息的接受时间排序，最新的消息排前面
type orderByMsgNoQueue struct {
	*listQueue
}

func (queue *orderByMsgNoQueue) PushFront(msg *Message) {
	tmp := queue.data.Front()
	if tmp == nil {
		queue.data.PushFront(msg)
		return
	}
	for tmp != nil && tmp.Value.(*Message).No > msg.No {
		tmp = tmp.Next()
	}
	if tmp == nil {
		queue.PushBack(msg)
	} else {
		queue.data.InsertBefore(msg, tmp)
	}
	if queue.Len() > queue.maxLen {
		queue.PopBack()
	}
}

func (queue *orderByMsgNoQueue) PushBack(msg *Message) {
	tmp := queue.data.Back()
	if tmp == nil {
		queue.data.PushBack(msg)
		return
	}
	for tmp != nil && tmp.Value.(*Message).No < msg.No {
		tmp = tmp.Prev()
	}
	if tmp == nil {
		queue.PushFront(msg)
	} else {
		queue.data.InsertAfter(msg, tmp)
	}
	if queue.Len() > queue.maxLen {
		queue.PopBack()
	}
}

type listQueue struct {
	maxLen int
	data   list.List
}

func NewListQueue(maxLen int) Queue {
	q := &listQueue{
		maxLen: maxLen,
		data:   list.List{},
	}
	q.data.Init()
	return q
}

func (queue *listQueue) Len() int {
	return queue.data.Len()
}

func (queue *listQueue) PushFront(msg *Message) {
	if queue.Len() >= queue.maxLen {
		queue.PopBack()
	}
	queue.data.PushFront(msg)
}

func (queue *listQueue) PushBack(msg *Message) {
	if queue.Len() >= queue.maxLen {
		return
	}
	queue.data.PushBack(msg)
}
func (queue *listQueue) PopFront() (*Message, bool) {
	f := queue.data.Front()
	if f != nil {
		queue.data.Remove(f)
		return f.Value.(*Message), true
	}
	return nil, false
}

func (queue *listQueue) PopBack() (*Message, bool) {
	f := queue.data.Back()
	if f != nil {
		queue.data.Remove(f)
		return f.Value.(*Message), true
	}
	return nil, false
}

func (queue *listQueue) Front() (*Message, bool) {
	if queue.Len() == 0 {
		return nil, false
	}
	msg := queue.data.Front()
	return msg.Value.(*Message), true
}

func (queue *listQueue) Back() (*Message, bool) {
	if queue.Len() == 0 {
		return nil, false
	}
	msg := queue.data.Back()
	return msg.Value.(*Message), true
}

func (q *listQueue) Wait() <-chan struct{} {
	panic("not implemented")
}

func (q *listQueue) Size() int {
	return q.maxLen
}